package mytree

import (
	"strings"

	"gitee.com/hailib/mytree/errs"
	"github.com/jmoiron/sqlx"
)

type Error = errs.Error

type MyTree interface {
	// Database 获取内部使用的 *sqlx.DB
	DB() *sqlx.DB

	// AddBranch 添加一个新的分支
	//   ordinal 分支的顺序
	AddBranch(parentId Id, name string, ordinal int64) (branchId Id, err Error)

	// DelBranch 删除分支
	DelBranch(branchId Id) (int64, Error)

	// DelTreeBranch 删除某棵树的子分支
	DelTreeBranch(rootId Id, branchId Id) (int64, Error)

	// getById 根据 id 查询分支
	GetById(branchId Id) (*Branch, Error)

	// MoveBranch 移动分支
	//   1. 移动分支时并不会检查树的总分支数
	//   2. 移动分支时，如果父节点的子分支数量太多，将会返回一个错误
	//   3. 如果父分支没有发生变化则直接返回
	//   4. 如果根分支不一样将返回错误
	//   5. 不能将自已移动到自已的后代分支下面
	MoveBranch(branchId Id, parentId Id) Error

	// MoveBranchTx 使用事务移动分支
	//   1. 移动分支时并不会检查树的总分支数
	//   2. 移动分支时，如果父节点的子分支数量太多，将会返回一个错误
	//   3. 如果父分支没有发生变化则直接返回
	//   4. 如果根分支不一样将返回错误
	//   5. 不能将自已移动到自已的后代分支下面
	//   6. 如果移动分支失败，事务将会被回滚
	MoveBranchTx(tx *sqlx.Tx, branchId Id, parentId Id) Error

	// NewTree 添加新的树，一个所有者允许有多棵树，每棵树之间互不干扰
	//   owner 所有者
	//   name  不允许包含如下特殊字符串： "/"
	NewTree(owner Id, name string) (branchId Id, err Error)

	// NewTreeTx 添加新的树，一个所有者允许有多棵树，每棵树之间互不干扰
	//   如果分支添加失败，事务将会被回滚
	//   owner 所有者
	//   name  不允许包含如下特殊字符串： "/"
	NewTreeTx(tx *sqlx.Tx, owner Id, name string) (branchId Id, err Error)

	// SelectTree 获取某棵树的所有分支
	SelectTree(branchId Id) ([]*Branch, Error)

	// SelectBranch 查找分支自身及所有的下级分支
	SelectBranch(branchId Id) ([]*Branch, Error)

	// SetBranch 设置分支属性
	SetBranch(branchId Id, name string, ordinal int64, clientdata string) Error

	// SetOrdinal 设置子分组的顺序
	SetOrdinal(parent Id, ordinals map[Id]int64) (int64, Error)

	// SetOrdinalTx 设置子分组的顺序
	SetOrdinalTx(tx *sqlx.Tx, parent Id, ordinals map[Id]int64) (int64, Error)

	// AddLeafs 添加一系列的叶子
	AddLeafs(branchId Id, leafs ...Id) Error

	// AddLeafsTx 添加一系列的叶子
	//
	// 如果执行失败，事务将会被回滚
	AddLeafsTx(stx *sqlx.Tx, branchId Id, leafs ...Id) Error

	// DelLeafsOfBranch 删除某个分支下面的一系列叶子，并返回实际被删除的 id 列表
	DelLeafsOfBranch(rootId Id, branchId Id, leafs ...Id) ([]Id, Error)

	// DelLeafsOfBranchTx 删除某个分支下面的一系列叶子，并返回实际被删除的 id 列表
	//   * 如果删除失败，事务会被自动回滚
	//   * 如果删除成功，事务并不会自动提交
	DelLeafsOfBranchTx(stx *sqlx.Tx, rootId Id, branchId Id, leafs ...Id) ([]Id, Error)

	// DelLeafTx 从整个数据库中删除叶子，并返回受影响的分支数组
	//   * 如果删除失败，事务将会被回滚
	//   * 删除过程中，叶子所属的所有树都会被锁定
	DelLeafTx(stx *sqlx.Tx, leafId Id) ([]Id, Error)

	// SelectBranchLeafs 查找分支直接拥有的叶子
	SelectBranchLeafs(branchId Id) ([]*Leaf, Error)

	// SelectBranchLeafsTx 查找分支直接拥有的叶子
	SelectBranchLeafsTx(stx *sqlx.Tx, branchId Id) ([]*Leaf, Error)

	// SelectLeafBranchs 查找叶子所属的所有分组
	SelectLeafBranchs(rootId Id, leaf Id) ([]*Leaf, Error)

	// SelectLeafBranchsTx 查找叶子所属的所有树
	//   1. 如果查询失败事务被自动回滚，但查询成功时事务不会被自动提交
	SelectLeafBranchsTx(stx *sqlx.Tx, rootId Id, leaf Id) ([]*Leaf, Error)

	// SelectLeafRoots 查找叶子所属的所有根节点
	SelectLeafRoots(leaf Id) ([]Id, Error)

	// SelectBranchLeafPage 分页查找分支直接拥有的叶子
	SelectBranchLeafPage(branchId Id, page int, size int) ([]*Leaf, Error)
}

// CheckBranchName 验证名称是否合法
func CheckBranchName(name string) Error {
	pos := strings.Index(name, "/")
	if pos != -1 {
		return errs.New(errs.InvalidParam, 210901161154, "invalid name: %s", name)
	}
	return nil
}
